
#include <sstream>
#include "util.h"
#include "context.h"
#include "ActionBase.h"
#include "usermgr.h"
#include "ordermgr.h"


class ActionGameApi
{
protected:
    enum ErrorCode {
        EC_NONE = 0,
        EC_BetAlready = 1,
        EC_MoneyNotEnough = 2,
        EC_InputParameterError = 3,
        EC_TokenExpire = 4,
        EC_OtherErr = 5,
        EC_RoundNotFound = 6,
        EC_BetAlreadyAcceptCantCancle = 7,
        EC_Failed = 9999,
    };
    static std::string ErrToString(ErrorCode ec_code)
    {
        std::string error_msg = "";
        switch (ec_code)
        {
            case EC_NONE: error_msg = "Success"; break;
            case EC_BetAlready: error_msg = "Already accepted"; break;
            case EC_MoneyNotEnough: error_msg = "Not enough balance"; break;
            case EC_InputParameterError: error_msg = " Invalid parameter"; break;
            case EC_TokenExpire: error_msg = "Token expired"; break;
            case EC_RoundNotFound: error_msg = "Round not found";break;
            case EC_BetAlreadyAcceptCantCancle: error_msg = "Already accepted and cannot be canceled"; break;
            
            default: error_msg = "unknowed errcode"; break;
        }
        return error_msg;
    }

public:
    static bool Init()
    {
        Ctx.msg_router.BindHttpHandle("post", "/auth", ActionGameApi::Auth);
        Ctx.msg_router.BindHttpHandle("post", "/balance", ActionGameApi::Balance);
        Ctx.msg_router.BindHttpHandle("post", "/bet", ActionGameApi::Bet);
        Ctx.msg_router.BindHttpHandle("post", "/cancelBet", ActionGameApi::CancleBet);
        Ctx.msg_router.BindHttpHandle("post", "/sessionBet", ActionGameApi::SessionBet);
        Ctx.msg_router.BindHttpHandle("post", "/cancelSessionBet", ActionGameApi::CancleSessionBet);
        Ctx.msg_router.BindHttpHandle("post", "/reward", ActionGameApi::Reward);
        return true;
    }
    
protected:
    static void Response(std::uint32_t request_id, ErrorCode err, const std::string& username, const std::string& currency, std::int64_t balance)
    {
        Json::Value json;
        json["username"] = username;
        json["balance"] = balance / 1000.0;
        json["currency"] = currency;
        json["errorCode"] = (int)err;
        json["message"] = ErrToString(err);
        std::map<std::string,std::string> heads;
        heads["Content-Type"] = "application/json";
        Ctx.msg_router.httpServerBack(request_id, 200, heads, CTools::ToStr(json));
    }

public:
    static void Auth(HttpData&& http_data)
    {
        log_debug("enter,request_id:%d", http_data.request_id);
        ErrorCode err = EC_NONE;
        std::string username = "";
        std::string currency = "";
        std::int64_t balance = 0;
        do
        {
            log_debug("Handle start, str::%s", http_data.body.c_str());

            Json::Value json;
            if (!CTools::FromStr(json, http_data.body))
            {
                err = EC_InputParameterError;
                log_error("parser json failed, str::%s", http_data.body.c_str());
                break;
            }
            /*
            reqId:xxxx, token:xxxx
            */
            std::string token;
            if (!json.isMember("token") || !json["token"].isString())
            {
                 err = EC_InputParameterError;
                 log_error("parser token failed, str::%s", http_data.body.c_str());
                 break;
            }
            token = json["token"].asString();
            
            username = TokenToUsername(token);
            stUser* st_user = UserMgr::Instance()->Get(username);
            if (st_user == nullptr)
            {
                err = EC_TokenExpire;
                log_error("GetUser failed, username:%s", username.c_str());
                break;
            }
            currency = st_user->currency;
            balance = st_user->balance;
        } while (false);
        log_debug("Handle over, id:%d, err:%d, username:%s", http_data.request_id, err, username.c_str());
        Response(http_data.request_id, err, username, currency, balance);
    }
    static void Balance(HttpData&& http_data)
    {
        log_debug("enter,request_id:%d", http_data.request_id);
        ErrorCode err = EC_NONE;
        std::string username = "";
        std::string currency = "";
        std::int64_t balance = 0;
        do
        {
            log_debug("Handle start, str::%s", http_data.body.c_str());

            Json::Value json;
            if (!CTools::FromStr(json, http_data.body))
            {
                err = EC_InputParameterError;
                log_error("parser json failed, str::%s", http_data.body.c_str());
                break;
            }
            /*
            reqId:xxxx, token:xxxx
            */
            std::string token;
            if (!json.isMember("token") || !json["token"].isString())
            {
                 err = EC_InputParameterError;
                 log_error("parser token failed, str::%s", http_data.body.c_str());
                 break;
            }
            token = json["token"].asString();
            
            username = TokenToUsername(token);
            stUser* st_user = UserMgr::Instance()->Get(username);
            if (st_user == nullptr)
            {
                err = EC_TokenExpire;
                log_error("GetUser failed, username:%s", username.c_str());
                break;
            }
            currency = st_user->currency;
            balance = st_user->balance;
        } while (false);
        log_debug("Handle over, id:%d, err:%d, username:%s", http_data.request_id, err, username.c_str());
        Response(http_data.request_id, err, username, currency, balance);
    }
    static void Bet(HttpData&& http_data)
    {
        log_debug("enter,request_id:%d", http_data.request_id);
        ErrorCode err = EC_NONE;
        std::string username = "";
        std::string currency = "";
        std::int64_t balance = 0;
        do
        {
            log_debug("Handle start, str::%s", http_data.body.c_str());

            Json::Value json;
            if (!CTools::FromStr(json, http_data.body))
            {
                err = EC_InputParameterError;
                log_error("parser json failed, str::%s", http_data.body.c_str());
                break;
            }
            /*
            reqId:xxxx, token:xxxx, currency:xxxx, game:xxxx, round:xxxx, betAmount:xxxx, winloseAmount:xxxx
            */
            std::string token;
            if (!json.isMember("token") || !json["token"].isString())
            {
                 err = EC_InputParameterError;
                 log_error("parser token failed, str::%s", http_data.body.c_str());
                 break;
            }
            token = json["token"].asString();
            if (!json.isMember("currency") || !json["currency"].isString())
            {
                 err = EC_InputParameterError;
                 log_error("parser currency failed, str::%s", http_data.body.c_str());
                 break;
            }
            currency = json["currency"].asString();
            std::int32_t game;
            if (!json.isMember("game") || !json["game"].isInt())
            {
                 err = EC_InputParameterError;
                 log_error("parser game failed, str::%s", http_data.body.c_str());
                 break;
            }
            game = json["game"].asInt();
            std::int64_t round;
            if (!json.isMember("round") || !json["round"].isInt64())
            {
                 err = EC_InputParameterError;
                 log_error("parser round failed, str::%s", http_data.body.c_str());
                 break;
            }
            round = json["round"].asInt64();
            std::int64_t betAmount;
            if (!json.isMember("betAmount") || !json["betAmount"].isDouble())
            {
                 err = EC_InputParameterError;
                 log_error("parser betAmount failed, str::%s", http_data.body.c_str());
                 break;
            }
            betAmount = json["betAmount"].asDouble() * 1000;
            std::int64_t winloseAmount;
            if (!json.isMember("winloseAmount") || !json["winloseAmount"].isDouble())
            {
                 err = EC_InputParameterError;
                 log_error("parser winloseAmount failed, str::%s", http_data.body.c_str());
                 break;
            }
            winloseAmount = json["winloseAmount"].asDouble() * 1000;

            username = TokenToUsername(token);
            stUser* st_user = UserMgr::Instance()->Get(username);
            if (st_user == nullptr)
            {
                err = EC_TokenExpire;
                log_error("GetUser failed, str::%s", http_data.body.c_str());
                break;
            }
            if (currency.compare(st_user->currency) != 0)
            {
                err = EC_InputParameterError;
                log_error("currency match failed, str::%s", http_data.body.c_str());
                break;
            }
            if (st_user->balance < betAmount)
            {
                err = EC_MoneyNotEnough;
                log_error("money not enough, balance:%lld, str::%s", st_user->balance, http_data.body.c_str());
                break;
            }

            std::stringstream cycle;
            cycle << game << ":" << round << ":" << username;

            stOrder* st_order = OrderMgr::Instance()->Get(cycle.str(), true);
            if (st_order == nullptr)
            {
                err = EC_OtherErr;
                log_error("order get failed, str::%s", http_data.body.c_str());
                break;
            }
            if (st_order->bet_orders.end() != st_order->bet_orders.find(cycle.str()))
            {
                err = EC_BetAlready;
                log_error("bet repeated, str::%s", http_data.body.c_str());
                break;
            }

            balance = st_user->balance -= betAmount - winloseAmount;

            st_order->bet_orders[cycle.str()] = betAmount;
            st_order->win_orders[cycle.str()] = winloseAmount;
            st_order->bet_amount += betAmount;
            st_order->bet_cnt += 1;
            st_order->win_amount += winloseAmount;
            st_order->win_cnt += 1;

        } while (false);
        log_debug("Handle over, id:%d, err:%d, username:%s", http_data.request_id, err, username.c_str());
        Response(http_data.request_id, err, username, currency, balance);
    }
    static void CancleBet(HttpData&& http_data)
    {
        log_debug("enter,request_id:%d", http_data.request_id);
        ErrorCode err = EC_NONE;
        std::string username = "";
        std::string currency = "";
        std::int64_t balance = 0;
        do
        {
            log_debug("Handle start, str::%s", http_data.body.c_str());

            Json::Value json;
            if (!CTools::FromStr(json, http_data.body))
            {
                err = EC_InputParameterError;
                log_error("parser json failed, str::%s", http_data.body.c_str());
                break;
            }
            /*
            reqId:xxxx, token:xxxx, currency:xxxx, game:xxxx, round:xxxx, betAmount:xxxx, winloseAmount:xxxx
            */
            std::string token;
            if (!json.isMember("token") || !json["token"].isString())
            {
                 err = EC_InputParameterError;
                 log_error("parser token failed, str::%s", http_data.body.c_str());
                 break;
            }
            token = json["token"].asString();
            if (!json.isMember("currency") || !json["currency"].isString())
            {
                 err = EC_InputParameterError;
                 log_error("parser currency failed, str::%s", http_data.body.c_str());
                 break;
            }
            currency = json["currency"].asString();
            std::int32_t game;
            if (!json.isMember("game") || !json["game"].isInt())
            {
                 err = EC_InputParameterError;
                 log_error("parser game failed, str::%s", http_data.body.c_str());
                 break;
            }
            game = json["game"].asInt();
            std::int64_t round;
            if (!json.isMember("round") || !json["round"].isInt64())
            {
                 err = EC_InputParameterError;
                 log_error("parser round failed, str::%s", http_data.body.c_str());
                 break;
            }
            round = json["round"].asInt64();
            std::int64_t betAmount;
            if (!json.isMember("betAmount") || !json["betAmount"].isDouble())
            {
                 err = EC_InputParameterError;
                 log_error("parser betAmount failed, str::%s", http_data.body.c_str());
                 break;
            }
            betAmount = json["betAmount"].asDouble() * 1000;
            std::int64_t winloseAmount;
            if (!json.isMember("winloseAmount") || !json["winloseAmount"].isDouble())
            {
                 err = EC_InputParameterError;
                 log_error("parser winloseAmount failed, str::%s", http_data.body.c_str());
                 break;
            }
            winloseAmount = json["winloseAmount"].asDouble() * 1000;

            username = TokenToUsername(token);
            stUser* st_user = UserMgr::Instance()->Get(username);
            if (st_user == nullptr)
            {
                err = EC_TokenExpire;
                log_error("GetUser failed, str::%s", http_data.body.c_str());
                break;
            }
            if (currency.compare(st_user->currency) != 0)
            {
                err = EC_InputParameterError;
                log_error("currency match failed, str::%s", http_data.body.c_str());
                break;
            }
            if (st_user->balance < winloseAmount - betAmount)
            {
                err = EC_MoneyNotEnough;
                log_error("money not enough, balance:%lld, str::%s", st_user->balance, http_data.body.c_str());
                break;
            }

            std::stringstream cycle;
            cycle << game << ":" << round << ":" << username;

            stOrder* st_order = OrderMgr::Instance()->Get(cycle.str(), true);
            if (st_order == nullptr)
            {
                err = EC_OtherErr;
                log_error("order get failed, str::%s", http_data.body.c_str());
                break;
            }
            if (st_order->cancle_orders.end() != st_order->cancle_orders.find(cycle.str()))
            {
                err = EC_BetAlready;
                log_error("cancle repeated, str::%s", http_data.body.c_str());
                break;
            }
            if (st_order->cancled_orders.end() != st_order->cancled_orders.find(cycle.str()))
            {
                err = EC_Failed;
                log_error("bet already cancle, str::%s", http_data.body.c_str());
                break;
            }
            auto it_bet = st_order->bet_orders.find(cycle.str());
            if (st_order->bet_orders.end() == it_bet)
            {
                err = EC_Failed;
                log_error("bet cycle not found, str::%s", http_data.body.c_str());
                break;
            }
            auto it_win = st_order->win_orders.find(cycle.str());
            if (st_order->win_orders.end() == it_bet)
            {
                err = EC_Failed;
                log_error("win cycle not found, str::%s", http_data.body.c_str());
                break;
            }
            if (it_bet->second != betAmount)
            {
                err = EC_Failed;
                log_error("bet amount not match, str::%s", http_data.body.c_str());
                break;
            }
            if (it_win->second != winloseAmount)
            {
                err = EC_Failed;
                log_error("winlose amount not match, str::%s", http_data.body.c_str());
                break;
            }

            balance = st_user->balance += betAmount - winloseAmount;

            st_order->cancled_orders.emplace(cycle.str());
            st_order->cancle_orders[cycle.str()] = cycle.str();
            st_order->bet_amount -= betAmount;
            st_order->bet_cnt -= 1;
            st_order->win_amount -= winloseAmount;
            st_order->win_cnt -= 1;

        } while (false);
        log_debug("Handle over, id:%d, err:%d, username:%s", http_data.request_id, err, username.c_str());
        Response(http_data.request_id, err, username, currency, balance); 
    }
    static void SessionBet(HttpData&& http_data)
    {
        log_debug("enter,request_id:%d", http_data.request_id);
        ErrorCode err = EC_NONE;
        std::string username = "";
        std::string currency = "";
        std::int64_t balance = 0;
        do
        {
            log_debug("Handle start, str::%s", http_data.body.c_str());

            Json::Value json;
            if (!CTools::FromStr(json, http_data.body))
            {
                err = EC_InputParameterError;
                log_error("parser json failed, str::%s", http_data.body.c_str());
                break;
            }
            /*
            reqId:xxxx, token:xxxx, currency:xxxx, game:xxxx, round:xxxx, betAmount:xxxx, winloseAmount:xxxx, type:xxxx, preserve:xxxx, sessionId:xxxxx 
            */
            std::string token;
            if (!json.isMember("token") || !json["token"].isString())
            {
                 err = EC_InputParameterError;
                 log_error("parser token failed, str::%s", http_data.body.c_str());
                 break;
            }
            token = json["token"].asString();
            if (!json.isMember("currency") || !json["currency"].isString())
            {
                 err = EC_InputParameterError;
                 log_error("parser currency failed, str::%s", http_data.body.c_str());
                 break;
            }
            currency = json["currency"].asString();
            std::int32_t game;
            if (!json.isMember("game") || !json["game"].isInt())
            {
                 err = EC_InputParameterError;
                 log_error("parser game failed, str::%s", http_data.body.c_str());
                 break;
            }
            game = json["game"].asInt();
            std::int64_t sessionId;
            if (!json.isMember("sessionId") || !json["sessionId"].isInt64())
            {
                 err = EC_InputParameterError;
                 log_error("parser sessionId failed, str::%s", http_data.body.c_str());
                 break;
            }
            sessionId = json["sessionId"].asInt64();
            std::int64_t round;
            if (!json.isMember("round") || !json["round"].isInt64())
            {
                 err = EC_InputParameterError;
                 log_error("parser round failed, str::%s", http_data.body.c_str());
                 break;
            }
            round = json["round"].asInt64();
            std::int32_t type;
            if (!json.isMember("type") || !json["type"].isInt64())
            {
                 err = EC_InputParameterError;
                 log_error("parser type failed, str::%s", http_data.body.c_str());
                 break;
            }
            type = json["type"].asInt64();
            std::int64_t betAmount;
            if (!json.isMember("betAmount") || !json["betAmount"].isDouble())
            {
                 err = EC_InputParameterError;
                 log_error("parser betAmount failed, str::%s", http_data.body.c_str());
                 break;
            }
            betAmount = json["betAmount"].asDouble() * 1000;
            std::int64_t winloseAmount;
            if (type != 1)
            {
                if (!json.isMember("winloseAmount") || !json["winloseAmount"].isDouble())
                {
                    err = EC_InputParameterError;
                    log_error("parser winloseAmount failed, str::%s", http_data.body.c_str());
                    break;
                }
            }
            winloseAmount = json["winloseAmount"].asDouble() * 1000;
            std::int64_t preserve;
            if (!json.isMember("preserve") || !json["preserve"].isDouble())
            {
                 err = EC_InputParameterError;
                 log_error("parser preserve failed, str::%s", http_data.body.c_str());
                 break;
            }
            preserve = json["preserve"].asDouble() * 1000;
            
            username = TokenToUsername(token);
            stUser* st_user = UserMgr::Instance()->Get(username);
            if (st_user == nullptr)
            {
                err = EC_TokenExpire;
                log_error("GetUser failed, str::%s", http_data.body.c_str());
                break;
            }
            if (currency.compare(st_user->currency) != 0)
            {
                err = EC_InputParameterError;
                log_error("currency match failed, str::%s", http_data.body.c_str());
                break;
            }
            balance = st_user->balance;
            
            std::stringstream cycle;
            cycle << game << ":" << sessionId << ":" << username;
            std::stringstream order;
            order << game << ":" << sessionId << ":" << round << ":" << username;

            if (type == 1)
            {
                stOrder* st_order = OrderMgr::Instance()->Get(cycle.str(), true);
                if (st_order == nullptr)
                {
                    err = EC_OtherErr;
                    log_error("order get failed, str::%s", http_data.body.c_str());
                    break;
                }
                if (st_order->bet_orders.end() != st_order->bet_orders.find(order.str()))
                {
                    err = EC_BetAlready;
                    log_error("order repeated, str::%s", http_data.body.c_str());
                    break;
                }

                if (preserve > 0)
                {
                    if (st_user->balance < preserve)
                    {
                        err = EC_MoneyNotEnough;
                        log_error("money not enough, balance:%lld, str::%s", st_user->balance, http_data.body.c_str());
                        break;
                    }
                    balance = st_user->balance -= preserve;
                    st_order->bet_orders[order.str()] = preserve;
                    st_order->bet_amount += preserve;
                    st_order->bet_cnt += 1;
                }
                else
                {
                    if (st_user->balance < betAmount)
                    {
                        err = EC_MoneyNotEnough;
                        log_error("money not enough, balance:%lld, str::%s", st_user->balance, http_data.body.c_str());
                        break;
                    }
                    balance = st_user->balance -= betAmount;
                    st_order->bet_orders[order.str()] = betAmount;
                    st_order->bet_amount += betAmount;
                    st_order->bet_cnt += 1;
                }
            }
            else if (type == 2)
            {
                stOrder* st_order = OrderMgr::Instance()->Get(cycle.str(), false);
                if (st_order == nullptr)
                {
                    err = EC_OtherErr;
                    log_error("order get failed, str::%s", http_data.body.c_str());
                    break;
                }
                if (st_order->win_orders.end() != st_order->win_orders.find(order.str()))
                {
                    err = EC_BetAlready;
                    log_error("order repeated, str::%s", http_data.body.c_str());
                    break;
                }
                std::int64_t delt = 0;
                if (preserve > 0)
                {
                    delt = winloseAmount + preserve - betAmount;
                }
                else
                {
                    delt = winloseAmount;
                }
                balance = st_user->balance += delt;

                st_order->win_orders[order.str()] = delt;
                st_order->win_amount += delt;
                st_order->win_cnt += 1;
            }
            else
            {
                err = EC_InputParameterError;
                log_error("type not match, str::%s", http_data.body.c_str());
                break;
            }

        } while (false);
        log_debug("Handle over, id:%d, err:%d, username:%s", http_data.request_id, err, username.c_str());
        Response(http_data.request_id, err, username, currency, balance);
    }
    static void CancleSessionBet(HttpData&& http_data)
    {
        log_debug("enter,request_id:%d", http_data.request_id);
        ErrorCode err = EC_NONE;
        std::string username = "";
        std::string currency = "";
        std::int64_t balance = 0;
        do
        {
            log_debug("Handle start, str::%s", http_data.body.c_str());

            Json::Value json;
            if (!CTools::FromStr(json, http_data.body))
            {
                err = EC_InputParameterError;
                log_error("parser json failed, str::%s", http_data.body.c_str());
                break;
            }
            /*
            reqId:xxxx, token:xxxx, currency:xxxx, game:xxxx, round:xxxx, betAmount:xxxx, winloseAmount:xxxx, type:xxxx, preserve:xxxx, sessionId:xxxxx 
            */
            std::string token;
            if (!json.isMember("token") || !json["token"].isString())
            {
                 err = EC_InputParameterError;
                 log_error("parser token failed, str::%s", http_data.body.c_str());
                 break;
            }
            token = json["token"].asString();
            if (!json.isMember("currency") || !json["currency"].isString())
            {
                 err = EC_InputParameterError;
                 log_error("parser currency failed, str::%s", http_data.body.c_str());
                 break;
            }
            currency = json["currency"].asString();
            std::int32_t game;
            if (!json.isMember("game") || !json["game"].isInt())
            {
                 err = EC_InputParameterError;
                 log_error("parser game failed, str::%s", http_data.body.c_str());
                 break;
            }
            game = json["game"].asInt();
            std::int64_t sessionId;
            if (!json.isMember("sessionId") || !json["sessionId"].isInt64())
            {
                 err = EC_InputParameterError;
                 log_error("parser sessionId failed, str::%s", http_data.body.c_str());
                 break;
            }
            sessionId = json["sessionId"].asInt64();
            std::int64_t round;
            if (!json.isMember("round") || !json["round"].isInt64())
            {
                 err = EC_InputParameterError;
                 log_error("parser round failed, str::%s", http_data.body.c_str());
                 break;
            }
            round = json["round"].asInt64();
            std::int32_t type;
            if (!json.isMember("type") || !json["type"].isInt64())
            {
                 err = EC_InputParameterError;
                 log_error("parser type failed, str::%s", http_data.body.c_str());
                 break;
            }
            type = json["type"].asInt64();
            std::int64_t betAmount;
            if (!json.isMember("betAmount") || !json["betAmount"].isDouble())
            {
                 err = EC_InputParameterError;
                 log_error("parser betAmount failed, str::%s", http_data.body.c_str());
                 break;
            }
            betAmount = json["betAmount"].asDouble() * 1000;
            if (type != 1)
            {
                err = EC_InputParameterError;
                log_error("parser winloseAmount failed, str::%s", http_data.body.c_str());
                break;
            }
            std::int64_t preserve;
            if (!json.isMember("preserve") || !json["preserve"].isDouble())
            {
                 err = EC_InputParameterError;
                 log_error("parser preserve failed, str::%s", http_data.body.c_str());
                 break;
            }
            preserve = json["preserve"].asDouble() * 1000;
            
            username = TokenToUsername(token);
            stUser* st_user = UserMgr::Instance()->Get(username);
            if (st_user == nullptr)
            {
                err = EC_TokenExpire;
                log_error("GetUser failed, str::%s", http_data.body.c_str());
                break;
            }
            if (currency.compare(st_user->currency) != 0)
            {
                err = EC_InputParameterError;
                log_error("currency match failed, str::%s", http_data.body.c_str());
                break;
            }
            
            std::stringstream cycle;
            cycle << game << ":" << sessionId << ":" << username;
            std::stringstream order;
            order << game << ":" << sessionId << ":" << round << ":" << username;

            stOrder* st_order = OrderMgr::Instance()->Get(cycle.str(), true);
            if (st_order == nullptr)
            {
                err = EC_OtherErr;
                log_error("order get failed, str::%s", http_data.body.c_str());
                break;
            }
            if (st_order->cancle_orders.end() != st_order->cancle_orders.find(cycle.str()))
            {
                err = EC_BetAlready;
                log_error("cancle repeated, str::%s", http_data.body.c_str());
                break;
            }
            if (st_order->cancled_orders.end() != st_order->cancled_orders.find(cycle.str()))
            {
                err = EC_Failed;
                log_error("bet already cancle, str::%s", http_data.body.c_str());
                break;
            }
            auto it_bet = st_order->bet_orders.find(order.str());
            if (st_order->bet_orders.end() == it_bet)
            {
                err = EC_Failed;
                log_error("bet cycle not found, str::%s", http_data.body.c_str());
                break;
            }

            if (preserve > 0)
            {
                if (it_bet->second != preserve)
                {
                    err = EC_Failed;
                    log_error("preserve amount not match, str::%s", http_data.body.c_str());
                    break;
                }
                balance = st_user->balance += preserve;
                st_order->bet_amount -= preserve;
                st_order->bet_cnt -= 1;
            }
            else
            {
                if (it_bet->second != betAmount)
                {
                    err = EC_Failed;
                    log_error("bet amount not match, str::%s", http_data.body.c_str());
                    break;
                }
                balance = st_user->balance += betAmount;
                st_order->bet_amount -= betAmount;
                st_order->bet_cnt -= 1;
            }
            st_order->cancle_orders[order.str()] = order.str();
            st_order->cancled_orders.emplace(order.str());

        } while (false);
        log_debug("Handle over, id:%d, err:%d, username:%s", http_data.request_id, err, username.c_str());
        Response(http_data.request_id, err, username, currency, balance);
    }
    static void Reward(HttpData&& http_data)
    {
        log_debug("enter,request_id:%d", http_data.request_id);
        ErrorCode err = EC_NONE;
        std::string username = "";
        std::string currency = "";
        std::int64_t balance = 0;
        do
        {
            log_debug("Handle start, str::%s", http_data.body.c_str());

            Json::Value json;
            if (!CTools::FromStr(json, http_data.body))
            {
                err = EC_InputParameterError;
                log_error("parser json failed, str::%s", http_data.body.c_str());
                break;
            }
            /*
            token:xxxx, currency:xxxx, game:xxxx, orderid:xxxx, amount:xxxx
            */
            std::string token;
            if (!json.isMember("token") || !json["token"].isString())
            {
                 err = EC_InputParameterError;
                 log_error("parser token failed, str::%s", http_data.body.c_str());
                 break;
            }
            token = json["token"].asString();
            if (!json.isMember("currency") || !json["currency"].isString())
            {
                 err = EC_InputParameterError;
                 log_error("parser currency failed, str::%s", http_data.body.c_str());
                 break;
            }
            currency = json["currency"].asString();
            std::int32_t game;
            if (!json.isMember("game") || !json["game"].isInt())
            {
                 err = EC_InputParameterError;
                 log_error("parser game failed, str::%s", http_data.body.c_str());
                 break;
            }
            game = json["game"].asInt();
            std::int64_t orderid;
            if (!json.isMember("orderid") || !json["orderid"].isInt64())
            {
                 err = EC_InputParameterError;
                 log_error("parser orderid failed, str::%s", http_data.body.c_str());
                 break;
            }
            orderid = json["orderid"].asInt64();
            std::int64_t amount;
            if (!json.isMember("amount") || !json["amount"].isDouble())
            {
                 err = EC_InputParameterError;
                 log_error("parser amount failed, str::%s", http_data.body.c_str());
                 break;
            }
            amount = json["amount"].asDouble() * 1000;

            username = TokenToUsername(token);
            stUser* st_user = UserMgr::Instance()->Get(username);
            if (st_user == nullptr)
            {
                err = EC_TokenExpire;
                log_error("GetUser failed, str::%s", http_data.body.c_str());
                break;
            }
            if (currency.compare(st_user->currency) != 0)
            {
                err = EC_InputParameterError;
                log_error("currency match failed, str::%s", http_data.body.c_str());
                break;
            }
            
            std::stringstream order;
            order << game << ":" << orderid << ":" << username;

            // stOrder* st_order = OrderMgr::Instance()->Get(order.str(), false);
            // if (st_order == nullptr)
            // {
            //     err = EC_OtherErr;
            //     log_error("order get failed, str::%s", http_data.body.c_str());
            //     break;
            // }
            // if (st_order->win_orders.end() != st_order->win_orders.find(order.str()))
            // {
            //     err = EC_BetAlready;
            //     log_error("order repeated, str::%s", http_data.body.c_str());
            //     break;
            // }
            
            balance = st_user->balance += amount;

            // st_order->win_orders[order.str()] = amount;
            // st_order->win_amount += amount;
            // st_order->win_cnt += 1;

        } while (false);
        log_debug("Handle over, id:%d, err:%d, username:%s", http_data.request_id, err, username.c_str());
        Response(http_data.request_id, err, username, currency, balance);
    }
};

static bool __init__ = ActionGameApi::Init();

